﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Redbrick.Silverlight.UI;

namespace Moria.Silverlight.Model
{
	public class Tile : Observable
	{

		#region Consts & Settings

		private const string PathToTileResource = "Resources/tiles.png";
		public const int Width = 32; // pixels
		public const int Height = 32; // pixels

		#endregion Consts & Settings

		#region Declarations

		private static Lazy<WriteableBitmap> tileSource = new Lazy<WriteableBitmap>(Tile.InitTileSource);
		private static Dictionary<string, WriteableBitmap> imageCache = new Dictionary<string, WriteableBitmap>();

		private bool _locked = false;

		#endregion Declarations

		#region Constructor

		static Tile() { }


		#endregion Constructor

		#region Methods

		static private WriteableBitmap InitTileSource()
		{
			WriteableBitmap bmp = new WriteableBitmap(0, 0).FromResource(PathToTileResource);
			return bmp;
		}
		static public explicit operator ImageSource (Tile tile)
		{
			if (tile.Image == null)
				tile.UpdateTile();
			return tile.Image;
		}

		protected override bool OnPropertyChanged(PropertyChangedEventArgs args)
		{
			if (args.PropertyName == "X" ||
				 args.PropertyName == "Y")
			{
				if (!this._locked) 
					this.UpdateTile();
			}

			if (args.PropertyName == "Image")
				this.RaiseImageChange();

			return base.OnPropertyChanged(args);
		}
		protected override bool OnPropertyChanging(PropertyChangingEventArgs args)
		{
			if (args.PropertyName == "Image" && this._locked)
			{
				args.Canceled = this._locked;
			}
			return base.OnPropertyChanging(args);
		}
		protected void RaiseImageChange()
		{
			WriteLineIf(this.IsDebug, "Raised Image Changed event");
			if (this.ImageUpdated != null)
				this.ImageUpdated(this, new EventArgs());
		}
		public bool LockTile() { return this._locked = true; }
		public bool UnlockTile(bool raiseChangedEvent = false)
		{

			this._locked = false;
			if (raiseChangedEvent)
			{
				this.UpdateTile();
			}
			return this._locked;
		}

		public WriteableBitmap UpdateTile()
		{

			string key = this.X + "." + this.Y;
			WriteableBitmap bmp = null;
			if (!imageCache.ContainsKey(key))
			{

				Rect sourceRect = new Rect(this.X * Tile.Width, this.Y * Tile.Height, Tile.Width, Tile.Height);
				Rect destRect = new Rect(0, 0, Tile.Width, Tile.Height);

				bmp = new WriteableBitmap(Tile.Width, Tile.Height);
				bmp.Clear(Colors.Transparent);
				bmp.Blit(destRect, Tile.TileSource, sourceRect);
				imageCache[key] = bmp;
			}
			else
			{
				bmp = imageCache[key];
			}
			this.Image = bmp;
			return bmp;
		}

		#endregion Methods

		#region Events

		public event EventHandler<EventArgs> ImageUpdated;

		#endregion Events

		#region Properties

		static public WriteableBitmap TileSource { get { return tileSource.Value; } }

		public int X
		{
			get { return this.GetValue(() => this.X); }
			set { this.SetValue(value, () => this.X); }
		}
		public int Y
		{
			get { return this.GetValue(() => this.Y); }
			set { this.SetValue(value, () => this.Y); }
		}
		public WriteableBitmap Image
		{
			get { return this.GetValue(() => this.Image); }
			set { this.SetValue(value, () => this.Image); }
		}

		#endregion Properties
	}
}
